package com.changhai.diabetes.action;

import java.beans.IntrospectionException;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.ezmorph.bean.MorphDynaBean;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.arcsoft.common.util.JsonUtil;
import com.changhai.diabetes.model.QueryDTO;
import com.changhai.diabetes.model.page.Page;
import com.changhai.diabetes.util.Constants;
import com.changhai.diabetes.util.JSON2JavaUtil;

/**
 * 
 * @author Andy
 *
 */
public abstract class BasePaginationAction extends BaseAction {
	private static final long serialVersionUID = -1713715065200680959L;
	private static Logger log = Logger.getLogger(BasePaginationAction.class);
	public static final Pattern p = Pattern.compile(Constants.SEARCH_FIELD_DATE_REGEX, Pattern.CASE_INSENSITIVE);
	// Your result List
	private List<Object> gridModel;

	// get how many rows we want to have into the grid - rowNum attribute in the
	// grid
	private Integer rows = 20;

	// Get the requested page. By default grid sets this to 1.
	private Integer page = 0;

	// sorting order - asc or desc
	private String sord;

	// get index row - i.e. user click to sort.
	private String sidx;

	// Search Field
	private String searchField;

	// The Search String
	private String searchString;

	// he Search Operation
	// ['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc']
	private String searchOper;

	// Your Total Pages
	private Integer total = 0;

	// All Record
	private Integer records = 0;

	private boolean _search = false;

	private String filters;

	// 翻页时保存前一次页面参数
	private String parametes = "";
	// 翻页时保存翻页的url
	private String saveUrl = "";

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.struts2.dispatcher.DefaultActionSupport#execute()
	 */
	@Override
	public String execute() throws Exception {
		return super.execute();
	}

	public String query() {
		return pageQuery();
	}

	protected String pageQuery() {
		int to = (rows);
		int from = rows * ((page - 1) <= 0 ? 0 : (page - 1));
		QueryDTO conditions = populateSearchConditions();
		conditions.getConditions().put(Constants.SEARCH_FROM, Integer.valueOf(from));
		conditions.getConditions().put(Constants.SEARCH_TO, Integer.valueOf(to));

		// 获取页面指定的额外参数
		String[] par = parametes.split("&");
		for (String s : par) {
			String[] kv = s.split("=");
			if (kv.length == 2 && !kv[0].equals("token")) {
				// 设置值
				invokeMethod(this, createMethodName(kv[0], "set"), new Object[] { kv[1] });
			}
		}

		Page page = searchQuery(conditions);

		// 获得所有页面传递的参数
		StringBuilder sb = new StringBuilder();
		Enumeration enums = getRequest().getParameterNames();
		while (enums.hasMoreElements()) {
			String paramName = (String) enums.nextElement();
			String value = getRequest().getParameter(paramName);
			if (value != null && !paramName.equals("token") && !paramName.equals("parametes") && value.length() > 0) {
				if (sb.length() > 0) {
					sb.append("&");
				}
				sb.append(paramName);
				sb.append("=");
				sb.append(value);
			}
		}

		parametes = sb.toString();
		this.records = page.getTotalNumberOfElements();
		this.gridModel = page.getThisPageElements();

		// this.records= 0;

		// calculate the total pages for the query
		total = (int) Math.ceil((double) records / (double) rows);

		com.arcsoft.common.Page page2 = new com.arcsoft.common.Page(this.page, rows, page.getTotalNumberOfElements(),
				parametes, saveUrl);
		getRequest().setAttribute("page", page2);
		getRequest().setAttribute("result", page.getThisPageElements());
		getRequest().setAttribute("count", page.getTotalNumberOfElements());
		return "input";
	}

	private QueryDTO populateSearchConditions() {
		if (this._search) {
			QueryDTO dto = new QueryDTO();
			Map conditions = new HashMap();
			// Mutil conditions
			if (null != filters && filters.length() > 0) {
				try {
					Object jsonObj = JsonUtil.toBean(filters, HashMap.class);
					if (jsonObj instanceof Map) {
						Map jsonMap = (Map) jsonObj;
						if (jsonMap.containsKey(Constants.SEARCH_GROUPOP)) {
							dto.setConnector((String) jsonMap.get(Constants.SEARCH_GROUPOP));
						}
						if (jsonMap.containsKey(Constants.SEARCH_RULE)) {
							Object ruleObj = jsonMap.get(Constants.SEARCH_RULE);
							if (ruleObj instanceof List) {
								List rules = (List) ruleObj;
								for (Iterator iter = rules.iterator(); iter.hasNext();) {
									Map map = (Map) iter.next();

									String fieldName = (String) map.get(Constants.SEARCH_FIELD);
									Matcher m = p.matcher(fieldName);
									if (m.find()) {
										String op = (String) map.get(Constants.SEARCH_OP);
										if (Constants.SEARCH_OP_VALUE_GQ.equalsIgnoreCase(op)) {
											conditions.put(Constants.SEARCH_FIELD_DATE_PREFIX + fieldName, map
													.get(Constants.SEARCH_DATA));
										} else {
											conditions.put(Constants.SEARCH_FIELD_DATE_SUFFIX + fieldName, map
													.get(Constants.SEARCH_DATA));
										}
									} else {
										conditions.put(fieldName, map.get(Constants.SEARCH_DATA));
									}
								}
							}
						}
					}
				} catch (Exception e) {
					log.error("Pagination populateSearchConditions occurred exception :\r\n  " + e.getMessage(), e);
				}
			} else {
				if (null != searchOper && null != searchString && null != searchField) {
					dto.setConnector(searchOper);
					conditions.put(searchField, searchString);
				}
			}
			dto.setConditions(conditions);
			return dto;
		}
		return new QueryDTO();
	}

	protected List populate2List(String params, Class<?> clazz) {
		List<Object> result = new ArrayList<Object>();
		try {
			String mapedParams = "{map: " + params + "}";
			Map re = (Map) JsonUtil.toBean(mapedParams, HashMap.class);
			Object jsonObj = re.get("map");
			if (jsonObj instanceof List<?>) {
				List<Object> list = (List<Object>) jsonObj;
				for (Iterator<?> i = list.iterator(); i.hasNext();) {
					MorphDynaBean values = (MorphDynaBean) i.next();
					Object obj = clazz.newInstance();
					JSON2JavaUtil.populateObject(obj, values);
					result.add(obj);
				}
			}
		} catch (IllegalAccessException e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		} catch (InvocationTargetException e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		} catch (IntrospectionException e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		} catch (InstantiationException e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		} catch (Exception e) {
			log.error("populate2List occurred exception :\r\n " + e.getMessage(), e);
		}
		return result;
	}


	/**
	 * 反射调用方法
	 * 
	 * @param owner
	 * @param methodName
	 * @param args
	 * @return
	 * @throws Exception
	 */
	private Object invokeMethod(Object owner, String methodName, Object[] args) {
		Class ownerClass = owner.getClass();
		Class[] argsClass = new Class[args.length];

		for (int i = 0, j = args.length; i < j; i++) {
			argsClass[i] = args[i].getClass();
		}

		Method method;
		try {
			method = ownerClass.getMethod(methodName, argsClass);
			return method.invoke(owner, args);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 根据属性名称，获得set方法名称
	 * 
	 * @param attr
	 * @param method
	 *            "set" OR "get"
	 * @return
	 */
	private String createMethodName(String attr, String method) {
		StringBuilder sb = new StringBuilder(attr);
		sb.replace(0, 1, sb.substring(0, 1).toUpperCase());
		sb.insert(0, method);
		return sb.toString();

	}

	/**
	 * Your logic to search and select the required data.
	 * 
	 * @param queryDTO
	 *            : the search conditions params
	 * @return
	 */
	protected abstract Page searchQuery(QueryDTO queryDTO);

	public List<Object> getGridModel() {
		return gridModel;
	}

	public void setGridModel(List<Object> gridModel) {
		this.gridModel = gridModel;
	}

	public Integer getRows() {
		return rows;
	}

	public void setRows(Integer rows) {
		this.rows = rows;
	}

	public Integer getPage() {
		return page;
	}

	public void setPage(Integer page) {
		this.page = page;
	}

	public String getSord() {
		return sord;
	}

	public void setSord(String sord) {
		this.sord = sord;
	}

	public String getSidx() {
		return sidx;
	}

	public void setSidx(String sidx) {
		this.sidx = sidx;
	}

	public String getSearchField() {
		return searchField;
	}

	public void setSearchField(String searchField) {
		this.searchField = searchField;
	}

	public String getSearchString() {
		return searchString;
	}

	public void setSearchString(String searchString) {
		this.searchString = searchString;
	}

	public String getSearchOper() {
		return searchOper;
	}

	public void setSearchOper(String searchOper) {
		this.searchOper = searchOper;
	}

	public Integer getTotal() {
		return total;
	}

	public void setTotal(Integer total) {
		this.total = total;
	}

	public Integer getRecords() {
		return records;
	}

	public void setRecords(Integer records) {
		this.records = records;
	}

	/**
	 * @return the _search
	 */
	public boolean is_search() {
		return _search;
	}

	/**
	 * @return the filters
	 */
	public String getFilters() {
		return filters;
	}

	/**
	 * @param _search
	 *            the _search to set
	 */
	public void set_search(boolean _search) {
		this._search = _search;
	}

	/**
	 * @param filters
	 *            the filters to set
	 */
	public void setFilters(String filters) {
		this.filters = filters;
	}

	public String getParametes() throws UnsupportedEncodingException {
		return java.net.URLEncoder.encode(parametes, "utf-8");
	}

	public void setParametes(String parametes) throws UnsupportedEncodingException {
		this.parametes = java.net.URLDecoder.decode(parametes, "utf-8");
	}

	public String getSaveUrl() {
		return saveUrl;
	}

	public void setSaveUrl(String saveUrl) {
		this.saveUrl = saveUrl;
	}
}
